import processing.core.*; import processing.xml.*; import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import java.util.zip.*; public class wikipedia_one extends PApplet {
public void setup() {
  // applet setup
  size(640,480);
  background(0);
  smooth();
  // load font
  PFont georgia = loadFont("Georgia-14.vlw");
  textFont(georgia,14);
  textAlign(CENTER);
  loadArticles(STARTTITLE);
  // add middle article
  MIDDLEARTICLE = new Article(width/2,height/2,0,width/2,height/2,STARTTITLE,true);
  articles.add(MIDDLEARTICLE);
}
public void draw() {
  background(0);
  for(int i=0; i<articles.size(); i++) {
    Article article = (Article)articles.get(i);
    // draw line to article
    if(!article.flying) {
      stroke(LINECOLOR);
      //line(MIDDLEARTICLE.x, MIDDLEARTICLE.y, article.x, article.y);
    }
    // draw article
    article.render();
  }
}
public void mousePressed() {
  for(int i=0; i<articles.size(); i++) {
    Article article = (Article)articles.get(i);
    if(article.mouseIsOver()) {
      if(article.centered) {
        link("http://en.wikipedia.org/wiki/"+article.title);
      } else {
        // center article
        article.center();
        MIDDLEARTICLE = article;
        // fly others away
        for(int j=0; j<articles.size(); j++) {
          if(!articles.get(j).equals(article)) {
            Article flyarticle = (Article)articles.get(j);
            flyarticle.flyaway();
            // println(flyarticle.title+" is flying away");
          }
        }
        loadArticles(article.title);
      }
    }
  }
}

class Article {
  // position, destination
  float x;
  float y;
  float destinationx;
  float destinationy;
  // color
  float r;
  float g;
  float b;
  float opacity;
  // when flying away
  float anglefromparent;
  boolean flying;
  float speed;
  // main one in middle?
  boolean centered;
  // title
  String title;

  public Article(float startx, float starty, float angle, float destx, float desty, String thetitle, boolean iscentered) {
    x = startx;
    y = starty;
    destinationx = destx;
    destinationy = desty;
    title = thetitle;
    centered = iscentered;
    flying = false;
    r = random(255);
    g = random(255);
    b = random(255);
    speed = 5;
    anglefromparent = angle;
    opacity = 255;
    render();
  }
  public boolean equals(Object other) {
    Article otherarticle = (Article)other;
    return otherarticle.title == this.title;
  }
  public void render() {
    noStroke();
    if(!flying) {
      // update position
      float xdiff = destinationx - x;
      float ydiff = destinationy - y;
      x += xdiff/MOVELAG;
      y += ydiff/MOVELAG;
    } else {
      // fly awayyyy!
      if(opacity > 0) {
        speed -= FLYACCELERATION;
        opacity -= FADESPEED;
        float[] nextpos = assignPoint(x,y,anglefromparent,speed);
        x = nextpos[0];
        y = nextpos[1];
      } else {
        // remove once invisible
        articles.remove(this);
        // println("removing "+title);
      }
    }
    // write text if mouse is over
    if(mouseIsOver() || centered && !flying) {
      drawSelf(true);
    } else {
      drawSelf(false);
    }
  }
  public void drawSelf(boolean showtitle) {
    fill(r,g,b,opacity);
    ellipse(x,y,DIAMETER,DIAMETER);
    if(showtitle) {
      fill(255);
      text(title,x,y+TITLE_OFFSET);
    }
  } 
  public boolean mouseIsOver() {
    float radius = DIAMETER/2;
    float topbound = y+radius;
    float bottombound = y-radius;
    float leftbound = x-radius;
    float rightbound = x+radius;
    if(mouseX > leftbound && mouseX < rightbound && mouseY < topbound && mouseY > bottombound) {
      return true;
    } else {
      return false;
    }
  }
  public void center() {
    centered = true;
    destinationx = width/2;
    destinationy = height/2;
  }
  public void flyaway() {
    flying = true;
    anglefromparent = anglefromparent+random(-45,45);
  }
}

// initial vars
float angle = 0;
String normalizedtitle;
Article MIDDLEARTICLE;
ArrayList articles = new ArrayList();
ArrayList links = new ArrayList();
XMLElement linksobject;
XMLElement query;
XMLElement page;

final String STARTTITLE = "Ninjas";
// dimensions
final int DISTANCE = 200;
final int TITLE_OFFSET = 20;
final int DIAMETER = 10;
// color
final float LINECOLOR = 100;
// speed/motion
final int MOVELAG = 10;
final float FLYACCELERATION = .1f;
final float FADESPEED = 5;
// articles
boolean ALLOW_NON_ARTICLES = false;

public XMLElement loadXML(String url) {
  println(urlEscape(url)+"\n");
  return new XMLElement(this, urlEscape(url));
}
public String urlEscape(String url) {
  return url.replaceAll(" ","%20");
}
public float[] assignPoint(float x, float y, float angle, float distance) {
  float thisangle = map(angle, 0, 360, 0, TWO_PI);
  x = cos(thisangle)*distance+x;
  y = sin(thisangle)*distance+y;
  float[] returnvalues = {
    x,y        };
  return returnvalues;
}
public void loadArticles(String starttitle) {
  ArrayList links = new ArrayList();
  println("\n>> loading links for "+starttitle+"\n");
  // load in the XML
  XMLElement a = loadXML("http://en.wikipedia.org/w/api.php?action=query&normalize&redirects&format=xml&prop=links&titles="+starttitle);
  query = a.getChild(0);
  page = query.getChild(query.getChildCount()-1).getChild(0);
  normalizedtitle = page.getStringAttribute("title");
  // check to see if it's missing
  boolean missing;
  if(!(page.getStringAttribute("missing") == null)) {
    missing = true;
  } else {
    missing = false;
  }
  // print(missing);
  linksobject = page.getChild(0);
  // parse out the links
  for(int i=0; i<linksobject.getChildCount(); i++) {
    XMLElement link = linksobject.getChild(i);
    if(link.getIntAttribute("ns") == 0 || ALLOW_NON_ARTICLES) {
      links.add(link.getStringAttribute("title"));
    }
  }
  println(links.size()+" links");
  // add surrounding ones
  for(int i=0; i<links.size(); i++) {
    angle += 360/(float)links.size();
    float[] pos = assignPoint(width/2,height/2,angle,(DISTANCE+random(-10,10)));
    Article article = new Article(width/2,height/2,angle,pos[0],pos[1],(String)links.get(i),false);
    articles.add(article);
  }
}

  static public void main(String args[]) {     PApplet.main(new String[] { "wikimap" });  }}